4.3 Виджеты. Stack и Positioned
3 из 3 шагов пройдено

 Виджеты. Stack и Positioned

➡️Ссылка на репозиторий с кодом этого урока

Подготовка

  • В директорию lib/stateful_widgets  добавим новый файл с названием s4_stack_widget.dart
  • ⭕ Добавим в файл main.dart виджет StackExample()
import 'package:flutter/material.dart';  
  
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: "Flutter Course",
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
      ),
      home: Scaffold(
        body: StackExample()
      ),
    );
  }
}

 

Вёрстка слоями

Виджеты Stack и Positioned - позволяют размещать виджеты друг над другом, создавая эффекты наложения, значков уведомлений (бейджей), водяных знаков и многого другого.

В Column и Row, виджеты располагаются последовательно. Но что, если вам нужно разместить один виджет поверх другого? Например, текст на фоне изображения, иконку поверх аватара или значок "Новинка" на углу карточки товара? Именно для таких задач и предназначен Stack.

Виджет Stack

Это виджет-контейнер, который позволяет размещать список дочерних виджетов друг над другом.
Дочерние виджеты располагаются в порядке их следования в списке children: первый виджет будет находиться в самом низу стека, а последний — в самом верху.

По умолчанию, дочерние виджеты в Stack выравниваются в верхнем левом углу Stack и пытаются занять все доступное пространство, если их размер не ограничен.

Параметры виджета Stack:

  • children: Список виджетов, которые будут размещены в стеке.
  • alignment: Определяет, как дочерние виджеты будут выравниваться в Stack, если их размер меньше размера Stack. По умолчанию AlignmentDirectional.topStart (верхний левый угол).
  • fit: Определяет, как дочерние виджеты, не обернутые в Positioned, будут подстраиваться под размеры Stack. По умолчанию StackFit.loose (дочерние виджеты могут быть меньше Stack). StackFit.expand заставит их расшириться, чтобы заполнить Stack
  • overflow: Определяет, как обрабатываются дочерние виджеты, выходящие за границы Stack. По умолчанию Overflow.clip (обрезаются).

Файл s4_stack_widget.dart

class StackExample extends StatelessWidget {  
  const StackExample({super.key});  
  
  @override  
  Widget build(BuildContext context) {  
    return Stack(  
      children: <Widget>[  
        // Первый виджет (внизу)  
        Container(  
          width: 300,  
          height: 300,  
          color: Colors.red[200],  
        ),  
        // Второй виджет (выше первого)  
        Container(  
          width: 250,  
          height: 250,  
          color: Colors.green[200],  
        ),  
        // Третий виджет (выше второго)  
        Container(  
          width: 200,  
          height: 200,  
          color: Colors.blue[300],  
        ),  
      ],  
    );  
  }  
}

В этом примере три контейнера накладываются друг на друга, причем зеленый поверх красного, а синий поверх зеленого, так как они идут в таком порядке в списке children. Все они выравниваются по верхнему левому углу по умолчанию.

Теперь заменим контейнеры и сделаем выравнивание по центру, получится интересный эффект (как круговые диаграммы или цель для игры в darts)

Файл s4_stack_widget.dart

class StackExample extends StatelessWidget {  
  const StackExample({super.key});  
  
  @override  
  Widget build(BuildContext context) {  
    return Stack(  
      children: <Widget>[  
        // Первый виджет (внизу)  
        Center(  
          child: CircleAvatar(radius: 200, backgroundColor: Colors.red[200]),  
        ),  
        // Второй виджет (выше первого)  
        Center(  
          child: CircleAvatar(radius: 150, backgroundColor: Colors.green[200]),  
        ),  
        // Третий виджет (выше второго)  
        Center(  
          child: CircleAvatar(radius: 100, backgroundColor: Colors.blue[300]),  
        ),  
      ],  
    );  
  }  
}

Виджет Positioned

Это специальный виджет, который используется только как дочерний элемент виджета Stack. Он не является самостоятельным виджетом. Positioned оборачивает другой виджет и позволяет точно указать его положение и размер относительно границ родительского Stack.

Без Positioned, дочерние виджеты в Stack просто выравниваются согласно параметру alignment Stack и, возможно, расширяются согласно fit.

Positioned дает полный контроль над положением.

Ключевые параметры виджета Positioned:

  • child: Виджет, который вы хотите позиционировать внутри Stack.
  • top: Расстояние от верхней границы Stack до верхней границы дочернего виджета.
  • bottom: Расстояние от нижней границы Stack до нижней границы дочернего виджета.
  • left: Расстояние от левой границы Stack до левой границы дочернего виджета.
  • right: Расстояние от правой границы Stack до правой границы дочернего виджета.
  • width: Явно заданная ширина дочернего виджета.
  • height: Явно заданная высота дочернего виджета.

Важное замечание о параметрах Positioned:

  • Если вы задаете left и rightPositioned игнорирует width и пытается определить ширину дочернего виджета так, чтобы он растянулся от left до right.
  • Аналогично, если вы задаете top и bottomPositioned игнорирует height и пытается определить высоту дочернего виджета так, чтобы он растянулся от top до bottom.
  • Если вы задаете только left (или right) и/или только top (или bottom), а также width и height, виджет будет иметь заданные размеры и будет позиционирован относительно указанных границ.

Пример Positioned внутри Stack

В этом примере мы создаем Stack, который содержит два дочерних виджета: Container и Positioned. Синий Container заполняет весь Stack (поскольку он первый и не обернут в Positioned), а Positioned размещает красный Container в правом нижнем углу с отступами 10 единиц.

Stack(
  children: [
    Container(
      color: Colors.blue[],
    ),
    Positioned(
      bottom: 10, // Отступ 10 от нижней границы Stack
      right: 10,  // Отступ 10 от правой границы Stack
      child: Container(
        color: Colors.red,
        width: 50,
        height: 50,
      ),
    ),
  ],
)


Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий